package com.caimiao.miao.library.usb.logic;

import android.util.Log;

import com.caimiao.miao.library.usb.interfaces.ICmdUtil;
import com.caimiao.miao.library.usb.accessory.Command;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;

public class CmdUtil implements ICmdUtil {
    private static final String TAG = "CommandUtil";

    /****************************************************************************************/

    @Override
    public Command getCommand(int command, int value, int value2) {
        char[] result;
        switch (command) {
            case UsbCode.SET_TICKET_VALUE://出票
                result = new char[]{(char) command, 0x00, (char) value};
                break;
            case UsbCode.GET_TICKET_VALUE://出票结果
                result = new char[]{(char) command, 0x00, 0x00};
                break;
            case UsbCode.GET_INDUCTION_STATUS://感应
                result = new char[]{(char) command, 0x00, 0x00};
                break;
            case UsbCode.GET_CONNECT_STATUS://连接
                result = new char[]{(char) command, 0x00, 0x00};
                break;
            default:
                result = new char[]{(char) command, (char) value, (char) value2};
                break;
        }
        return getCommand(UsbCode.SCHEDULER_STATUS_WRITE, getCommand(result));
    }

    @Override
    public Command getCommand(@UsbCode.Code int status, char[] value) {
        return new Command(status, value);
    }

    @Override
    public char getCode(char[] command) {
        if (command != null && command.length > 3) return command[3];
        return 0;
    }

    @Override
    public char[] getCommand(char[] value) {
        byte checkSum = 0;
        int numBytes = value.length;
        char writeBuffer[] = new char[numBytes + 4];
        writeBuffer[0] = (char) 0x55;//开始位
        for (int i = 0; i < numBytes; i++) {//命令+数值
            writeBuffer[i + 2] = value[i];
        }
        writeBuffer[1] = (char) (numBytes + 4);//长度位
        for (int count = 0; count < numBytes + 2; count++) {
            checkSum += writeBuffer[count];
        }
        checkSum += 0x99;
        //校验位
        if (checkSum <= 0)
            writeBuffer[numBytes + 2] = (char) (-checkSum);
        else
            writeBuffer[numBytes + 2] = (char) (256 - checkSum);
        writeBuffer[numBytes + 3] = 0x99;//结束位
        return writeBuffer;
    }

    @Override
    public byte[] getBytes(char[] value) {
        char[] chars = getCommand(value);
        Charset cs = Charset.forName("UTF-8");
        CharBuffer cb = CharBuffer.allocate(chars.length);
        cb.put(chars);
        cb.flip();
        ByteBuffer bb = cs.encode(cb);
        return bb.array();
    }

    /****************************************************************************************/
    @Override
    public void returnCommand(char[] command) {
        switch ((int) command[2]) {
            case UsbCode.SET_TICKET_VALUE://出票设置成功
                break;
            case UsbCode.RET_TICKET_VALUE://返回出票结果
                break;
            case UsbCode.RET_INDUCTION_STATUS://返回感应结果
                break;
            case UsbCode.RET_CONNECT_STATUS://返回连接结果
                break;
        }
    }

    /**
     * 从value中得到一条完整的命令(可能有多条，后期再优化)
     *
     * @param value
     * @return
     */
    @Override
    public Command checkReadData(char[] value) {
        Command command = new Command(UsbCode.SCHEDULER_STATUS_READ, null);
        int length = value == null ? 0 : value.length;
        Log.e(TAG, "read: length = " + length);
        if (length < UsbCode.PACKAGE_LENGTH) return command;
        for (int i = 0; i <= length - UsbCode.PACKAGE_LENGTH; i++) {
            if (check(value, i, i + UsbCode.PACKAGE_LENGTH)) {
                char[] cmd = new char[UsbCode.PACKAGE_LENGTH];
                for (int j = 0; j < UsbCode.PACKAGE_LENGTH; j++) {
                    cmd[j] = value[j + i];
                }
                command.setCommand(cmd);
                break;
            }
        }
        return command;
    }

    /**
     * 判断是否为一条完整的命令
     *
     * @param read
     * @param start
     * @param end
     * @return
     */
    @Override
    public boolean check(char[] read, int start, int end) {
        //判断获取到的数据的正确性和完整性 55 07 c3 00 00 xx 99
        // 是否以55开始
//        Log.e(TAG, "read: " + (start + 0) + " = " + Integer.toHexString((int) read[start+ 0]));
//        Log.e(TAG, "read: " + (start + 1) + " = " + Integer.toHexString((int) read[start+ 1]));
//        Log.e(TAG, "read: " + (start + 2) + " = " + Integer.toHexString((int) read[start+ 2]));
//        Log.e(TAG, "read: " + (start + 3) + " = " + Integer.toHexString((int) read[start+ 3]));
//        Log.e(TAG, "read: " + (start + 4) + " = " + Integer.toHexString((int) read[start+ 4]));
//        Log.e(TAG, "read: " + (start + 5) + " = " + Integer.toHexString((int) read[start+ 5]));
//        Log.e(TAG, "read: " + (start + 6) + " = " + Integer.toHexString((int) read[start+ 6]));
        if (read[start] != UsbCode.PACKAGE_START)
            return false;
        // 长度是否一致
        if (read[start + 1] != UsbCode.PACKAGE_LENGTH)
            return false;
        // 是否以99结尾
        if (read[end - 1] != UsbCode.PACKAGE_END) {
            return false;
        }
        // checksum是否正确
        byte checkSum = 0;
        for (int i = start; i < end; i++) {
            checkSum += read[i];
        }
//        Log.e(TAG, "checkSum: " + checkSum);
        if (checkSum != 0) {
            return false;
        }
        // 判断返回的指令与发送的指令是否对应
//        if (!CHKCommand(sendStr[2], reports.charAt(s + 2))) {
//			report = ""; // 如果当前帧与发送的指令非对应关系则清除当前帧(为了处理缓存里会同时存在1帧以上指令的BUG)
//            return false;
//        }

        return true;
    }

    @Override
    public boolean isTicketOut(char[] command) {
        if (command.length > 3)
            return command[2] == UsbCode.GET_TICKET_VALUE;
        return false;
    }

    /**
     * 判断接收到的数据其命令是否与发送的命令一一对应
     *
     * @param send
     * @param report
     * @return 不对应返回False，对应返回True；
     */
    private boolean checkCommand(int send, int report) {
        if (send <= 0x3F && send >= 0x01) {            //Set命令，原代码返回
            return send == report;
        } else if (send <= 0xBF && send >= 0x81) {     //Get命令，与Ret比较——Get命令 + 0x40 = Ret命令
            return (send + 0x40) == report;
        } else {
            return false;
        }
    }
}
